#include <jni.h>
#include <android/log.h>
#include <string>

//http://www.voidcn.com/article/p-elqeblog-bps.html 各种格式字段内容解析
extern "C" {
#include "include/ffmpeg/libavformat/avformat.h"
#include "include/ffmpeg/libavutil/rational.h"
#include "include/ffmpeg/libavcodec/avcodec.h"
#include "include/ffmpeg/libavutil/dict.h"
#include "include/ffmpeg/libavutil/pixfmt.h"
#include "include/ffmpeg/libavutil/avutil.h"
}

#define TAG "FFMPEG"
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG,TAG ,__VA_ARGS__) // 定义LOGD类型
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO,TAG ,__VA_ARGS__) // 定义LOGI类型
#define LOGW(...) __android_log_print(ANDROID_LOG_WARN,TAG ,__VA_ARGS__) // 定义LOGW类型
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,TAG ,__VA_ARGS__) // 定义LOGE类型
#define LOGF(...) __android_log_print(ANDROID_LOG_FATAL,TAG ,__VA_ARGS__) // 定义LOGF类型

std::string convert2VideoInfoJsonString(JNIEnv env, AVFormatContext *pFormatCtx, int v_stream_idx, int a_stream_idx) {
    using namespace std;
    string jsonStr = string();
    jsonStr.append("{")
            .append("filePath : \"").append(pFormatCtx->url).append("\",\n")
            .append("width : ").append(std::to_string(pFormatCtx->streams[v_stream_idx]->codecpar->width)).append(",\n")
            .append("height : ").append(std::to_string(pFormatCtx->streams[v_stream_idx]->codecpar->height)).append(
                    ",\n")
            .append("profile : ").append(to_string(pFormatCtx->streams[v_stream_idx]->codecpar->profile)).append(",\n")
            .append("profileName : \"").append(
                    avcodec_profile_name(pFormatCtx->streams[v_stream_idx]->codecpar->codec_id,
                                         pFormatCtx->streams[v_stream_idx]->codecpar->profile)
                    ? avcodec_profile_name(pFormatCtx->streams[v_stream_idx]->codecpar->codec_id,
                                           pFormatCtx->streams[v_stream_idx]->codecpar->profile)
                    : "null"
            ).append("\",\n")
            .append("level : ").append(to_string(pFormatCtx->streams[v_stream_idx]->codecpar->level)).append(",\n")
            .append("bitsPerCodedSample : ").append(
                    to_string(pFormatCtx->streams[v_stream_idx]->codecpar->bits_per_coded_sample)).append(",\n")
            .append("videoPixelFormatType : ").append(
                    to_string(v_stream_idx > -1 ? pFormatCtx->streams[v_stream_idx]->codecpar->format
                                                : AV_PIX_FMT_NONE)).append(",\n")
            .append("audioSampleFormatType : ").append(to_string(
                    a_stream_idx > -1 ? pFormatCtx->streams[a_stream_idx]->codecpar->format
                                      : AV_SAMPLE_FMT_NONE)).append(
                    ",\n")
            .append("videoEncodeType : ").append(
                    to_string(pFormatCtx->streams[v_stream_idx]->codecpar->codec_id)).append(",\n")
            .append("videoEncodeName : \"").append(
                    avcodec_get_name(pFormatCtx->streams[v_stream_idx]->codecpar->codec_id)).append("\",\n")
            .append("audioEncodeType : ").append(
                    to_string(a_stream_idx > 0 ? pFormatCtx->streams[a_stream_idx]->codecpar->codec_id : -1)).append(
                    ",\n")
            .append("audioEncodeName : \"").append(
                    a_stream_idx > 0 ? avcodec_get_name(pFormatCtx->streams[a_stream_idx]->codecpar->codec_id)
                                     : "").append("\",\n")
            .append("bitRate : ").append(to_string(pFormatCtx->streams[v_stream_idx]->codecpar->bit_rate)).append(
                    ",\n")
            .append("avgFrameRateNum : ").append(
                    std::to_string(pFormatCtx->streams[v_stream_idx]->avg_frame_rate.num)).append(",\n")
            .append("avgFrameRateDen : ").append(
                    std::to_string(pFormatCtx->streams[v_stream_idx]->avg_frame_rate.den)).append(",\n")
            .append("frameRate : ").append(
                    std::to_string(av_q2d(pFormatCtx->streams[v_stream_idx]->r_frame_rate))).append(",\n")
            .append("formatName : \"").append(pFormatCtx->iformat->name).append("\",\n")

            .append("formatExtensionsName : \"").append(
                    pFormatCtx->iformat->extensions ? pFormatCtx->iformat->extensions : "null").append("\",\n")
            .append("formatLongName : \"").append(pFormatCtx->iformat->long_name).append("\"")
            .append("}");
    return jsonStr;
}

static void log_callback_null(void *ptr, int level, const char *fmt, va_list vl)
{
    static int print_prefix = 1;
    static int count;
    static char prev[1024];
    char line[1024];
    static int is_atty;

    av_log_format_line(ptr, level, fmt, vl, line, sizeof(line), &print_prefix);

    strcpy(prev, line);
    //sanitize((uint8_t *)line);

    if (level <= AV_LOG_WARNING)
    {
        LOGE("%s", line);
    }
    else
    {
        LOGD("%s", line);
    }
}

extern "C"
JNIEXPORT jstring JNICALL
Java_com_leon_android_ffmpeg_FFmpegHelper_getVideoInfoNative(JNIEnv *env, jclass type, jstring url_) {
    using namespace std;
    const char *url = env->GetStringUTFChars(url_, JNI_FALSE);
    LOGE("%s", url);
    std::string result = std::string("");

    int angle = -1;
    //1.注册所有组件  此方法已经废弃无需调用
    //av_register_all();
    //封装格式上下文
//    av_log_set_callback(log_callback_null);
    av_log_set_level(AV_LOG_INFO);
    AVFormatContext *pFormatCtx = avformat_alloc_context();
    //2.打开输入视频文件
    int openStatus = avformat_open_input(&pFormatCtx, url, NULL, NULL);
    if (openStatus != 0) {
        LOGD("%s%d", "open file failed! error code : ",openStatus);
        avformat_close_input(&pFormatCtx);
        avformat_free_context(pFormatCtx);
        return env->NewStringUTF(result.append("open file failed! error code : " + to_string(openStatus)).c_str());
    }
    LOGD("open file succeed!");
    //3.获取视频文件信息
    if (avformat_find_stream_info(pFormatCtx, NULL) < 0) {
        LOGE("%s", "can't get video info.");
        return env->NewStringUTF(result.append("can't get video info.").c_str());
    }

    LOGD("Get video info.");
    //获取视频流的索引位置
    int v_stream_idx = -1;
    int a_stream_idx = -1;
    int i = 0;
    for (i = 0; i < pFormatCtx->nb_streams; i++) {
        if (pFormatCtx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO && v_stream_idx == -1) {
            v_stream_idx = i;
            av_dump_format(pFormatCtx, v_stream_idx, "/storage", false);
        }
        if (pFormatCtx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO && a_stream_idx == -1) {
            a_stream_idx = i;
            av_dump_format(pFormatCtx, a_stream_idx, url, false);
        }
        if (a_stream_idx != -1 && v_stream_idx != -1) {
            break;
        }
    }
    LOGD("Get streams index!");

//获取视频方向数据
    AVDictionaryEntry *tag = NULL;
    tag = av_dict_get(pFormatCtx->streams[v_stream_idx]->metadata, "rotate", tag, 0);
    if (tag != NULL) {
        angle = atoi(tag->value);
        LOGD("%d", angle);
    }
    if (v_stream_idx != -1) {
        //宽度
        LOGD("video stream index ： %d", v_stream_idx);
        result.append(convert2VideoInfoJsonString(*env, pFormatCtx, v_stream_idx, a_stream_idx));
        LOGD("AV_PIX_FMT_YUV420P format int : %d", AV_PIX_FMT_YUV420P);
        LOGD("H264 encode int : %d", AV_CODEC_ID_H264);
    } else {
        result.append("Get streams index failed");
    }
    LOGD("%s", result.c_str());
    env->ReleaseStringUTFChars(url_, url);
    avformat_close_input(&pFormatCtx);
    avformat_free_context(pFormatCtx);
    return env->NewStringUTF(result.c_str());
}